import i18n from '../../../../i18n';
import type {
    DialogCloseData,
    DialogData,
    DialogKeyData,
} from '../../../../shares/sharesApp';
import { RemoteType } from '../../../../shares/sharesApp';
import { EventEmitter } from '../../framework/common/EventEmitter';
import { Singleton } from '../../framework/common/Singleton';
import { GameProgress } from '../const/GameProgress';
import { PlayerType } from '../const/TokenConst';
import { InteractMgr } from './InteractMgr';
import { NpcMgr } from './NpcMgr';
import { PlayerDataMgr } from './PlayerDataMgr';
import { PlayerMgr } from './PlayerMgr';
import { RemoteMgr } from './RemoteMgr';

/**
 * 游戏管理器 / GameManager
 */
export class GameMgr extends Singleton<GameMgr>() {
    /** 糖果列表 / Candy list */
    private _candys: GameEntity[] = [];
    /** 是否为毒药 / Is poison */
    private _isPoison: boolean[] = [];
    /** 是否初始化完成 / Is initialized */
    private _isInited: boolean = false;
    /*** 玩家列表 / Player list */
    private _players: string[] = [];
    /** 选择毒药的玩家 / Choose poison player */
    private _choosePoisonPlayer: string[] = [];
    /** 选择糖果的玩家 / Choose candy player */
    private _chooseCandyPlayer: number = 0;
    /** 游戏进度 */
    private _progress: GameProgress = GameProgress.Start;

    constructor() {
        super();
        console.log('(Server) GameMgr constructor');
    }

    /**
     * 启动 / Start
     * @param id 地图ID / Map ID
     */
    public start(id: number | string): void {
        if (id === 'play') {
            this.bindEvents();
            const interval = setInterval(async () => {
                if (this._players.length >= 2) {
                    clearInterval(interval);
                }
                world.say('Waiting .');
                await sleep(1000);
                world.say('Waiting . .');
                await sleep(1000);
                world.say('Waiting . . .');
            }, 3000);
        } else if (id === 'main') {
            this.bindJoinEvents();
        }
    }

    /**
     * 绑定事件 / Bind events
     */
    private bindEvents(): void {
        world.onPlayerJoin(({ entity }) => {
            if (this._players.length >= 2) {
                PlayerMgr.instance.link(
                    entity.player.userId,
                    '9cfc40f405a4ff70306d'
                );
                entity.player.kick();
            } else if (this._players.length < 2) {
                this._players.push(entity.player.userId);
                PlayerMgr.instance.changePlayerType(
                    entity.player.userId,
                    PlayerType.GamePlayer
                );
                if (this._players.length === 2) {
                    if (!this._isInited) {
                        this.init();
                    }
                }
            }
            console.log('(Server) player:', this._players);
        });
        world.onPlayerLeave(({ entity }) => {
            if (this._players.includes(entity.player.userId)) {
                this.end_1(
                    this._players.find((v) => v !== entity.player.userId)!,
                    entity.player.userId
                );
            }
            console.log('(Server) player:', this._players);
        });
    }

    /**
     * 绑定加入事件 / Bind join events
     */
    private bindJoinEvents(): void {
        world.onPlayerJoin(async ({ entity }) => {
            while (true) {
                const player = PlayerMgr.instance.getPlayer(
                    entity.player.userId
                );
                const playerData = PlayerDataMgr.instance.getPlayerData(
                    entity.player.userId
                );
                if (player && playerData) {
                    const subject = playerData.getSubject();
                    if (Date.now() - subject.lastLoginTime <= 30000) {
                        RemoteMgr.instance.send<DialogKeyData>(entity, {
                            type: RemoteType.DIALOG_KEY,
                            data: { key: 'first_login', params: {} },
                        });
                    }
                    break;
                }
                await sleep(100);
            }
        });
    }

    /**
     * 初始化 / Init
     */
    private async init() {
        this._isInited = true;
        await sleep(5000);
        console.log('(Server) Game init');
        RemoteMgr.instance.sendAll<DialogKeyData>({
            type: RemoteType.DIALOG_KEY,
            data: { key: 'game.start', params: {} },
        });
        this.createCandy();
        await sleep(1000);
        // 游戏开始
        this.choosePoison();
    }

    private choosePoison() {
        console.log('(Server) GameProgress: ChoosePoison');
        // 关闭对话UI / Close dialog UI
        RemoteMgr.instance.sendAll<DialogCloseData>({
            type: RemoteType.DIALOG_CLOSE,
            data: null,
        });
        // 修改进度为选择毒药 / Change progress to choose poison
        this._progress = GameProgress.ChoosePoison;
        setTimeout(async () => {
            if (this._progress !== GameProgress.ChoosePoison) {
                return;
            }
            RemoteMgr.instance.sendAll<DialogKeyData>({
                type: RemoteType.DIALOG_KEY,
                data: { key: 'game.choose_poison_timeout', params: {} },
            });
            await sleep(1000);
            this.chooseCandy();
        }, 30000);
        this._players.forEach(async (id) => {
            const player = PlayerMgr.instance.getPlayer(id);
            if (player?.entity) {
                const result: boolean = (await InteractMgr.instance.dialog(
                    'choose_poison',
                    player.entity
                )) as boolean;

                if (result) {
                    this._choosePoisonPlayer.push(id);
                }
            } else {
                console.log('(Server) 玩家不存在');
            }
        });
    }

    private async chooseCandy() {
        console.log('(Server) GameProgress: ChooseCandy');
        this._progress = GameProgress.ChooseCandy;
        let candyCount = 0;
        this._isPoison.forEach((item) => {
            if (!item) {
                candyCount++;
            }
        });
        this._chooseCandyPlayer = 0;
        while (candyCount--) {
            if (this._progress !== GameProgress.ChooseCandy) {
                return;
            }
            const player = PlayerMgr.instance.getPlayer(this.chooseCandyPlayer);
            RemoteMgr.instance.sendAll<DialogKeyData>({
                type: RemoteType.DIALOG_KEY,
                data: {
                    key: 'game.choose_candy',
                    params: { name: player?.entity?.player.name },
                },
            });

            await new Promise((resolve) => {
                // 超时直接死
                const timeout = setTimeout(() => {
                    this.end_1(
                        this._players.find(
                            (item) => item !== this.chooseCandyPlayer
                        )!,
                        this.chooseCandyPlayer
                    );
                    resolve();
                }, 30000);
                EventEmitter.instance.once('candyEat', (entity) => {
                    clearTimeout(timeout);
                    // 获取糖果索引 / Get candy index
                    const index = this._candys.findIndex(
                        (item) => item === entity
                    );
                    // 如果选择到毒药
                    if (this._isPoison[index]) {
                        this.end_1(
                            this._players.find(
                                (item) => item !== this.chooseCandyPlayer
                            )!,
                            this.chooseCandyPlayer
                        );
                    } else {
                        entity.destroy();
                        this._chooseCandyPlayer =
                            (this._chooseCandyPlayer + 1) % 2;
                    }
                    resolve();
                });
            });
        }

        // 结局2 / End 2
        this.end_2();
    }

    /**
     * 创建糖果 / Create candy
     */
    private createCandy(): void {
        const candyPosition = [
            new GameVector3(35, 13.3, 36),
            new GameVector3(36, 13.3, 36),
            new GameVector3(37, 13.3, 36),
            new GameVector3(38, 13.3, 36),
            new GameVector3(38, 13.3, 37),
            new GameVector3(38, 13.3, 38),
            new GameVector3(38, 13.3, 39),
            new GameVector3(37, 13.3, 39),
            new GameVector3(36, 13.3, 39),
            new GameVector3(35, 13.3, 39),
            new GameVector3(35, 13.3, 38),
            new GameVector3(35, 13.3, 37),

            new GameVector3(36, 13.3, 37),
            new GameVector3(37, 13.3, 38),
        ];
        for (let i = 0; i < candyPosition.length; i++) {
            const candy = world.createEntity({
                id: 'candy',
                mesh: 'mesh/万圣节大糖果.vb',
                collides: false,
                gravity: false,
                position: candyPosition[i],
            });
            if (candy) {
                this._candys.push(candy);
                this._isPoison.push(false);
            }
        }
        NpcMgr.instance.addNpcById('candy');
    }

    /**
     * 游戏进度 / Game progress
     * @returns {GameProgress}
     */
    public get progress(): GameProgress {
        return this._progress;
    }

    /**
     * 获取选择糖果的玩家 / Get choose candy player
     * 当游戏进度为<选择糖果>时，返回当前要选择糖果的玩家ID / When the game progress is <ChooseCandy>, return the player ID to choose candy</ChooseCandy>
     * @returns {string} 玩家ID / Player ID
     */
    public get chooseCandyPlayer(): string {
        return this._players[this._chooseCandyPlayer];
    }

    /**
     * 玩家是否能否选择糖果作为毒药 / Can player choose candy as poison
     * @param player 玩家ID / Player ID
     */
    public canChooseCandyAsPoison(player: string): boolean {
        return this._choosePoisonPlayer.includes(player);
    }

    /**
     * 将糖果作为毒药 / Make candy as poison
     * @param entity 糖果实体对象 / Candy entity object
     * @param player 玩家ID / Player ID
     */
    public candyAsPoison(entity: GameEntity, player: string): void {
        // 获取糖果索引 / Get candy index
        const index = this._candys.findIndex((item) => item === entity);
        if (this._progress === GameProgress.ChoosePoison) {
            if (this._choosePoisonPlayer.includes(player)) {
                if (this._isPoison[index] === false) {
                    this._isPoison[index] = true;
                }

                // 将该玩家移除
                this._choosePoisonPlayer = this._choosePoisonPlayer.filter(
                    (item) => item !== player
                );
            }
        }
        console.log('(Server) 当前糖果毒药状况:', this._isPoison);
        console.log(index);
    }

    /**
     * 结束游戏
     */
    private async end(): Promise<void> {
        this._progress = GameProgress.End;
        this._players.forEach((userId) => {
            EventEmitter.instance.once(`dialogEnd_${userId}`, () => {
                PlayerMgr.instance.link(userId, '9cfc40f405a4ff70306d');
            });
        });
        setTimeout(() => {
            world.querySelectorAll('player').forEach((entity) => {
                try {
                    PlayerMgr.instance.link(
                        entity.player.userId,
                        '9cfc40f405a4ff70306d'
                    );
                } finally {
                    entity.player.kick();
                }
            });
        }, 15000);
        setTimeout(() => {
            while (true) {}
        }, 20000);
    }

    /**
     * 结束游戏 / End game
     * @param winner 胜利者ID / Winner ID
     * @param loser 输者ID / Loser ID
     */
    private async end_1(winner: string, loser: string): Promise<void> {
        this.end();
        this.solveWinner(winner);
        this.solveLoser(loser);
        await sleep(5000);
        const winnerPlayer = PlayerMgr.instance.getPlayer(winner);
        const loserPlayer = PlayerMgr.instance.getPlayer(loser);
        RemoteMgr.instance.sendAll<DialogKeyData>({
            type: RemoteType.DIALOG_KEY,
            data: {
                key: 'game.end_1.result',
                params: {
                    winner: winnerPlayer?.entity?.player.name,
                    loser: loserPlayer?.entity?.player.name,
                },
            },
        });
    }

    /**
     * 解决游戏胜利者 / Solve game winner
     * @param userId 玩家ID / Player ID
     */
    private solveWinner(userId: string): void {
        const player = PlayerMgr.instance.getPlayer(userId);
        if (player) {
            RemoteMgr.instance.send<DialogData>(player.entity!, {
                type: RemoteType.DIALOG,
                data: {
                    title: '',
                    content: [i18n.t('game.end_1.win', { lng: player.lng })],
                },
            });
        } //记录
        const playerData = PlayerDataMgr.instance.getPlayerData(userId);
        if (playerData) {
            const subject = playerData.getSubject();
            playerData.setSubject({
                playCount: subject.playCount + 1 || 1,
                candy: subject.candy + 100 || 100,
                winCount: subject.winCount + 1 || 1,
                lastLoginTime: subject.lastLoginTime,
                lastLogoutTime: Date.now(),
            });
        }
    }

    /**
     * 解决游戏输者 / Solve game loser
     * @param userId 玩家ID / Player ID
     */
    private solveLoser(userId: string): void {
        const player = PlayerMgr.instance.getPlayer(userId);
        if (player) {
            RemoteMgr.instance.send<DialogData>(player.entity!, {
                type: RemoteType.DIALOG,
                data: {
                    title: '',
                    content: [i18n.t('game.end_1.lose', { lng: player.lng })],
                },
            });
        } //记录
        const playerData = PlayerDataMgr.instance.getPlayerData(userId);
        if (playerData) {
            const subject = playerData.getSubject();
            playerData.setSubject({
                playCount: subject.playCount + 1 || 1,
                candy: subject.candy || 0,
                winCount: subject.winCount || 1,
                lastLoginTime: subject.lastLoginTime,
                lastLogoutTime: Date.now(),
            });
        }
    }

    /**
     * 结束游戏 / End game
     */
    end_2(): void {
        this.end();
        const names = this._players.map((userId) => {
            const player = PlayerMgr.instance.getPlayer(userId);
            if (player) {
                return player.entity?.player.name;
            } else {
                return userId;
            }
        });
        RemoteMgr.instance.sendAll<DialogKeyData>({
            type: RemoteType.DIALOG_KEY,
            data: {
                key: 'game.end_2.result',
                params: { winner1: names[0], winner2: names[1] },
            },
        });
        this._players.forEach((userId) => {
            //记录
            const playerData = PlayerDataMgr.instance.getPlayerData(userId);
            if (playerData) {
                const subject = playerData.getSubject();
                playerData.setSubject({
                    playCount: subject.playCount + 1 || 1,
                    candy: subject.candy + 50 || 50,
                    winCount: subject.winCount + 1 || 1,
                    lastLoginTime: subject.lastLoginTime,
                    lastLogoutTime: Date.now(),
                });
            }
        });
    }
}
